// Sphere object

#include <math.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>

#include "../include/triangletexture.h"
#include "../include/colour.h"

#include "../my/include/Matrix.h"

// Plane defined as a vertex (in world space) as location
//                  and n which is the normal direction



TriangleTexture::TriangleTexture(Vertex &aa, Vertex &bb, Vertex &cc, PPMImage *img) {
	a = aa;
	b = bb;
	c = cc;
	typex = "Triangle";
	typei = 31;

	image = img;//readPPM("/Users/Peter/Desktop/f.ppm");
}

bool TriangleTexture::intersect(Ray &input_ray, Hit *hit) {
	//transform
	Ray ray = input_ray;
	if (transformed != 0) {
		ray.D.multiply(invers_matrix);
		ray.P.multiply(invers_matrix);
	}
	//N = (c-a)x(b-a)
	Vector N = (c - a).cross((b - a));

	//N.P’ = -d
	//N.a = -d;
	//P’ = P + tD ->  N.(P+tD) = -d -> t = N.P+N.tD = -d -> t = (-d – N.P) /N.D


	double t = (a.getVector().dot(N) - ray.P.getVector().dot(N)) / N.dot(ray.D);
	if (t < 0.00001) {
		return false;
	}

	Vector hitPoint;
	hitPoint.x = ray.P.x + ray.D.x * t;
	hitPoint.y = ray.P.y + ray.D.y * t;
	hitPoint.z = ray.P.z + ray.D.z * t;

	int tempa = 0;
	if (hitPoint.x > hitPoint.y) {
		if (hitPoint.z > hitPoint.x) {
			//z
			tempa = 3;
		} else {
			//x
			tempa = 1;
		}
	} else {
		if (hitPoint.z > hitPoint.y) {
			//z
			tempa = 3;
		} else {
			//y
			tempa = 2;
		}
	}

	Vector aa = a.getVector();
	Vector bb = b.getVector();
	Vector cc = c.getVector();

	Vector pp = hitPoint;
	if (tempa == 1) {
		aa.x = 0;
		bb.x = 0;
		cc.x = 0;
		pp.x = 0;
	} else if (tempa == 2) {
		aa.y = 0;
		bb.y = 0;
		cc.y = 0;
		pp.y = 0;
	} else if (tempa == 3) {
		aa.z = 0;
		bb.z = 0;
		cc.z = 0;
		pp.z = 0;
	}

	Vector temp1 = pp.subtract(aa).cross(bb.subtract(aa));
	Vector temp2 = pp.subtract(bb).cross(cc.subtract(bb));
	Vector temp3 = pp.subtract(cc).cross(aa.subtract(cc));

	int hited = 0;
	if (tempa == 1) {
		if (temp1.x > 0 && temp2.x > 0 && temp3.x > 0) {
			hited = 1;
		}
		if (temp1.x < 0 && temp2.x < 0 && temp3.x < 0) {
			hited = 1;
		}
	} else if (tempa == 2) {
		if (temp1.y > 0 && temp2.y > 0 && temp3.y > 0) {
			hited = 1;
		}
		if (temp1.y < 0 && temp2.y < 0 && temp3.y < 0) {
			hited = 1;
		}
	} else if (tempa == 3) {
		if (temp1.z > 0 && temp2.z > 0 && temp3.z > 0) {
			hited = 1;
		}
		if (temp1.z < 0 && temp2.z < 0 && temp3.z < 0) {
			hited = 1;
		}
	}

	if (hited != 0) {
		hit->obj = this;
		hit->t = t;

		hit->p.x = ray.P.x + t * ray.D.x;
		hit->p.y = ray.P.y + t * ray.D.y;
		hit->p.z = ray.P.z + t * ray.D.z;
		hit->p.w = 1.0;

		//cc -> p1  aa->p0  bb->p2
		//a = p - p0
		double A1 = hit->p.x - aa.x;
		double A2 = hit->p.y - aa.y;

		//b = p1 - p0;
		double B1 = bb.x - aa.x;
		double B2 = bb.y - aa.y;

		//c = p2-p0;
		double C1 = cc.x - aa.x;
		double C2 = cc.y - aa.y;

		if (tempa == 1) {
			//b = p1 - p0;
			B1 = bb.z - aa.z;
			B2 = bb.y - aa.y;
			//c = p2-p0;
			C1 = cc.z - aa.z;
			C2 = cc.y - aa.y;
		} else if (tempa == 2) {
			 B1 = bb.x - aa.x;
			 B2 = bb.z - aa.z;

			//c = p2-p0;
			 C1 = cc.x - aa.x;
			 C2 = cc.z - aa.z;
		} else if (tempa == 3) {
			 B1 = bb.x - aa.x;
			 B2 = bb.y - aa.y;

			//c = p2-p0;
			 C1 = cc.x - aa.x;
			 C2 = cc.y - aa.y;
		}

		double r = (A1 * B2 - B1 * A2) / (C1 * B2 - C2 * B1);
		//		double bt = (A1 - C1* r) / B1;

		double bt = (A1 * C2 - C1 * A2) / (B1 * C2 + B2 * C1);
		//r, bt are u,v


		double imgw = image->x;
		double imgh = image->y;

		double imgx = imgw * r;
		double imgy = imgh * bt;

		int imgintx = floor(imgx);
		int imginty = floor(imgy);

		int imgindex = imginty * imgw + imgintx;

		Colour co;
		double imgr = image->data[imgindex].red;
		double imgg = image->data[imgindex].green;
		double imgb = image->data[imgindex].blue;

		imgr = imgr / 255.0;
		imgg = imgg / 255.0;
		imgb = imgb / 255.0;
		co.set(imgr, imgg, imgb, 1);
		hit->obj_mat = *this->obj_mat;
		hit->obj_mat.ka = co;

		//		std::cout<<"r="<<r <<"bt="<<bt<<std::endl;

		hit->n.x = N.x;
		hit->n.y = N.y;
		hit->n.z = N.z;

		if (transformed != 0) {
			hit->n.multiply(invers_matrix);
		}
		hit->n.normalise();

		return true;
	} else {
		return false;
	}
}
